#include "TSintactico.h"

int TSintactico_Crear(TSintactico* as){
    int i;
    for(i=0;i<MAX_TOKEN;i++){
        as->tokensProcesados[i].tipo=VALOR_INICIAL;
        strcpy(as->tokensProcesados[i].dato,"");
    }
    as->proximo_dato = VALOR_INICIAL;
    as->codigoUltimoError=0;
    as->inicio_objeto=0;

    return 0;
}

int TSintactico_PushToken(TSintactico* as, Token* token){
	if(!as->inicio_objeto){
	    if(token->tipo==TOKEN_OBJETO_EMPIEZA){
            puts("OBJETO");
            as->inicio_objeto = 1;
            as->proximo_dato = CLAVE;
            return 0;
	    }
    }
    if(as->inicio_objeto){
        switch(as->proximo_dato){
            case CLAVE:      if(token->tipo==TOKEN_STRING){       /* aca espera un string, si recibe cualquier otra cosa es error*/
                                 as->proximo_dato = DOS_PUNTOS;
                                 guardar_token(as,token);
                             }
                             else{as->codigoUltimoError=ERROR_CLAVE;
                                   return 1;}
                             break;

            case DOS_PUNTOS: if(token->tipo==TOKEN_DOSPUNTOS){   /*debe recibir token DOS_PUNTOS, sino es error */
                                 as->proximo_dato = DATO_UNO;
                                 guardar_token(as,token);
                             }
                             else{as->codigoUltimoError=ERROR_DOSPUNTOS;
                                   imprimir_linea(as);
                                   return 1;}
                             break;

            case DATO_UNO:   if((token->tipo==TOKEN_STRING)||(token->tipo==TOKEN_NUMERO)||(token->tipo==TOKEN_TRUE)||(token->tipo==TOKEN_FALSE)||(token->tipo==TOKEN_NULL)){
                                 as->proximo_dato = COMA;
                                 guardar_token(as,token);
                                 break;
                             }
                             if(token->tipo==TOKEN_ARRAY_EMPIEZA){  /* por si recibo un arreglo */
                                 as->proximo_dato = DATO_ARRAY;
                                 guardar_token(as,token);
                                 break;
                             }
                             if(token->tipo==TOKEN_OBJETO_EMPIEZA){     /* por si recibo un objeto anidado */
                            	 as->codigoUltimoError=ERROR_OBJETO_ANIDADO;
                            	 imprimir_linea(as);
                            	 return 1;}
                             else{as->codigoUltimoError=ERROR_DATO;
                                   imprimir_linea(as);
                                   return 1;}
                             break;

            case DATO_ARRAY: if((token->tipo==TOKEN_STRING)||(token->tipo==TOKEN_NUMERO)){ /* se analiza dentro del arreglo */
                                 if(comprobar_tipo(as,token)){           /* comprueba que si se guardo un valor antes sea del mismo tipo del que se esta analizando  */
                                     as->codigoUltimoError=ERROR_ARRAY;
                                     imprimir_linea(as);
                                     return 1;
                                 }
                                 as->proximo_dato = COMA_ARRAY;
                                 guardar_token(as,token);
                                 break;
                             }
                             if(token->tipo==TOKEN_NULL){
                                 as->proximo_dato = COMA_ARRAY;
                                 guardar_token(as,token);
                                 break;
                             }
                             else{as->codigoUltimoError=ERROR_ARRAY;
                                   imprimir_linea(as);
                                   return 1;}
                             break;

            case COMA_ARRAY: if(token->tipo==TOKEN_COMA){
                                 as->proximo_dato = DATO_ARRAY;
                                 guardar_token(as,token);
                                 break;
                             }
                             if(token->tipo==TOKEN_ARRAY_TERMINA){
                                 as->proximo_dato = COMA;
                                 guardar_token(as,token);
                                 break;
                             }
                             else{as->codigoUltimoError=ERROR_ARRAY;
                                   imprimir_linea(as);
                                   return 1;}
                             break;

            case COMA:       if(token->tipo==TOKEN_COMA){
                                 as->proximo_dato = CLAVE;
                                 guardar_token(as,token);
                                 imprimir_linea(as);
                                 limpiar_tokens(as);
                                 break;
                             }
                             if(token->tipo==TOKEN_OBJETO_TERMINA){
                                 imprimir_linea(as);
                                 puts("FIN OBJETO");
                                 TSintactico_terminarFlujo(as);
                                 as->inicio_objeto = 0;
                                 break;
                             }
                             else{as->codigoUltimoError=ERROR_TERMINACION_LINEA;
                                   imprimir_linea(as);
                                   return 1;}


        }
    }
    else return 1;
    return 0;
}

/*           Funciones Auxiliares                     */

int guardar_token(TSintactico* as,Token* token){
    int i;
    for(i=0;i<MAX_TOKEN;i++){
        if((as->tokensProcesados)[i].tipo==VALOR_INICIAL){
            (as->tokensProcesados)[i].tipo = token->tipo;
            if(token->tipo==TOKEN_STRING||token->tipo==TOKEN_NUMERO)
                strcpy((as->tokensProcesados)[i].dato,token->dato);
            return 0;
        }
    }
    return 1;
}

void imprimir_linea(TSintactico* as){
    int i;
    printf("\tCLAVE: \"%s\" : ",as->tokensProcesados[0].dato);

    switch(as->tokensProcesados[2].tipo){
        case TOKEN_STRING: printf("(String) : \"%s\"\n",as->tokensProcesados[2].dato);
                           break;
        case TOKEN_NUMERO: printf("(Numero) : %s\n",as->tokensProcesados[2].dato);
                           break;
        case TOKEN_TRUE:   printf("(Boolean) : true\n");
                           break;
        case TOKEN_FALSE:  printf("(Boolean) : false\n");
                           break;
        case TOKEN_NULL:   printf("(Null) :\n");
                           break;
        case TOKEN_ARRAY_EMPIEZA: printf("(ARRAY) : ARRAY\n");
    	                          for(i=3;i<MAX_TOKEN-3||as->tokensProcesados[i].tipo==VALOR_INICIAL;i++){
    		                          if(as->tokensProcesados[i].tipo==TOKEN_ARRAY_TERMINA){
    			                          printf("\t\t\tFIN ARRAY\n");
    			                          break;
    		                          }
    		                          if(as->tokensProcesados[i].tipo==TOKEN_COMA)
    		                              continue;
    	                              if(as->tokensProcesados[i].tipo==TOKEN_STRING)
    			                          printf("\t\t\t\t(String) : \"%s\"\n",as->tokensProcesados[i].dato);

               		                  if(as->tokensProcesados[i].tipo==TOKEN_NUMERO)
    		                              printf("\t\t\t\t(Numero) : %s\n",as->tokensProcesados[i].dato);

        		                      if(as->tokensProcesados[i].tipo==TOKEN_NULL)
    		                              printf("\t\t\t\t(Null) :\n");
    	                          }
    }
}

int comprobar_tipo(TSintactico* as,Token* token){
    int resultado;
    int i;
    int j;

    resultado = 0;

    for(i=0;i<MAX_TOKEN && as->tokensProcesados[i].tipo!=VALOR_INICIAL;i++){
    }
    for (j=i; j>0 && as->tokensProcesados[j].tipo!=TOKEN_ARRAY_EMPIEZA; j--){
        if ( as->tokensProcesados[j].tipo==TOKEN_STRING || as->tokensProcesados[j].tipo==TOKEN_NUMERO ){
            if (as->tokensProcesados[j].tipo!=token->tipo){
                resultado=1;
                break;
            }
        }
    }
    return resultado;
}

int limpiar_tokens(TSintactico* as){
    int i;
    for(i=0;i<MAX_TOKEN;i++){
        as->tokensProcesados[i].tipo=VALOR_INICIAL;
        strcpy(as->tokensProcesados[i].dato,"");
    }
    return 0;
}
/*******************************************************/


int TSintactico_terminarFlujo(TSintactico* as){
	int i;
	for(i=0;i<MAX_TOKEN;i++){
	    as->tokensProcesados[i].tipo=VALOR_INICIAL;
	    strcpy(as->tokensProcesados[i].dato,"");
	}
	as->codigoUltimoError=0;
	as->inicio_objeto=0;
	as->proximo_dato=0;
	return 0;
}

int TSintactico_getUltimoError(TSintactico* as, int *codigo, char* mensaje){
    (*codigo)=as->codigoUltimoError;
    strcpy(mensaje,recuperarMensajeError(*codigo));
	return 0;
}

